package client

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"algo-sdk-go/common/tools"

	"github.com/zeromicro/go-zero/rest/httpx"
)

var appDefaultClient = http.Client{
	Timeout: time.Second * 3,
	Transport: &http.Transport{
		MaxIdleConnsPerHost: 2048,
		IdleConnTimeout:     time.Minute * 5,
	},
}

func ToRequestBody(obj any) io.Reader {
	if obj == nil {
		return nil
	}
	j, _ := json.Marshal(obj)
	return bytes.NewBuffer(j)
}

func SendRequest[T any](ctx context.Context, method, url string, requestBody io.Reader, headerMap map[string]string) (resp T, err error) {
	var respBody []byte
	respBody, err = RequestWithClient(appDefaultClient, ctx, method, url, requestBody, headerMap)
	if err != nil {
		return
	}

	resp, err = tools.JsonToObject[T](respBody)
	return
}

func RequestWithClient(client http.Client, ctx context.Context, method, url string, requestBody io.Reader, headerMap map[string]string) ([]byte, error) {
	method = strings.ToUpper(method)
	var resp *http.Response
	var request *http.Request
	var err error

	request, err = http.NewRequest(method, url, requestBody)
	if err != nil {
		return nil, err
	}
	for key, value := range headerMap {
		request.Header.Add(key, value)
	}

	switch method {
	case "GET":
		resp, err = client.Do(request)
	case "PUT", "POST", "DELETE":
		if request.Header.Get(httpx.ContentType) == "" {
			request.Header.Add("Content-Type", "application/json")
		}
		resp, err = client.Do(request)
	default:
		print("not exist method")
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	//TODO: errors.wrapf
	if resp.StatusCode != http.StatusOK {
		return nil, errors.New(fmt.Sprintf("http code err, resp.StatusCode %d", resp.StatusCode))
	}
	defer func(body io.ReadCloser) {
		_ = body.Close()
	}(resp.Body)
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
}
